/*
 * @Author: zhuxiaoyi
 * @Date: 2024-04-24 10:58:11
 * @LastEditor: zhuxiaoyi
 * @LastEditTime: 2024-07-02 17:26:53
 * @Description:
 */
import { Provide, App, Inject, Config } from '@midwayjs/core';
import { Ipage, IGraph, IAlgorithmParams } from '../interface';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Graph } from '../entity/graph.entity';
import { Application } from '@midwayjs/ws';
import { MiniTask } from '../entity/miniTask.entity';
import { Algorithm } from '../entity/algorithm.entity';
import { M1Product } from '../entity/module1.entity';
import { Repository, Like } from 'typeorm';
import * as childProcess from 'child_process';
import { PromiseService } from '../service/promise.service';
import axios from 'axios';
import * as fs from 'fs';
import * as path from 'path';
import * as archiver from 'archiver';

@Provide()
export class GraphService {
  @InjectEntityModel(Graph)
  GraphModel: Repository<Graph>;

  @InjectEntityModel(MiniTask)
  MiniTaskModel: Repository<MiniTask>;

  @InjectEntityModel(Algorithm)
  AlgorithmModel: Repository<Algorithm>;

  @Inject()
  promiseService: PromiseService;

  @App('webSocket')
  wsApp: Application;

  @Config('matlabExePath')
  matlabExePath;

  async getGraphList(params: Ipage) {
    const [result, total] = await this.GraphModel.findAndCount({
      where: { name: Like(`%${params.keyword ? params.keyword : ''}%`) },
      skip: (params.page_index - 1) * params.page_size,
      take: params.page_size,
      order: { createDate: 'DESC' },
    });
    return {
      succes: true,
      data: result,
      total,
      message: '成功',
    };
  }

  async getGraph(id: number) {
    const graph = await this.GraphModel.findOne({
      where: {
        id,
      },
    });
    if (!graph) {
      return {
        succes: false,
        message: '未查询到算法流程',
      };
    }
    return { success: true, data: graph, message: '算法流程查询成功 ' };
  }
  async getDynamicData(id: number) {
    const graph = await this.GraphModel.findOne({
      where: {
        id,
      },
    });
    if (!graph) {
      return {
        succes: false,
        message: '未查询到算法流程',
      };
    }
    return { success: true, data: JSON.parse(graph.dynamic), message: '流程模板字符串查询成功 ' };
  }
  async editDynamicData(id: number, dynamicData: any) {
    const graph = await this.GraphModel.findOne({
      where: {
        id,
      },
    });
    if (!graph) {
      return {
        succes: false,
        message: '未查询到算法流程',
      };
    }
    graph.dynamic = JSON.stringify(dynamicData)
    const graphResult = await this.GraphModel.save(graph);
    return { success: true, data: graphResult, message: '流程模板字符串查询成功 ' };
  }


  async addGraph(params: IGraph) {
    let graphData = JSON.parse(params.graph);
    let edges = [];
    let nodes = [];

    graphData.cells.forEach(element => {
      if (element.shape == 'edge') {
        edges.push(element);
      } else {
        nodes.push(element);
      }
    });
    const executionOrder = this.topologicalSort(edges);
    let graph = new Graph();
    graph.name = params.name;
    graph.graph = params.graph;
    graph.flow = JSON.stringify(executionOrder);
    const graphResult = await this.GraphModel.save(graph);
    if (graphResult) {
      this.createMiniTask(executionOrder, graphData, graph);
      return { success: true, data: graphResult, message: '图谱保存成功 ' };
    } else {
      return { success: false, message: '图谱保存失败 ' };
    }
  }

  async updateGraph(params: IGraph) {
    let graphData = JSON.parse(params.graph);
    let edges = [];
    let nodes = [];

    graphData.cells.forEach(element => {
      if (element.shape == 'edge') {
        edges.push(element);
      } else {
        nodes.push(element);
      }
    });
    const executionOrder = this.topologicalSort(edges);

    const graph = await this.GraphModel.findOne({
      where: {
        id: params.id,
      },
    });
    if (!graph) {
      return {
        succes: false,
        message: '未查询到算法流程',
      };
    }
    graph.name = params.name;
    graph.graph = params.graph;
    let diffResult;
    diffResult = await this.findArrayDiff(
      JSON.parse(graph.flow),
      executionOrder
    );
    graph.flow = JSON.stringify(executionOrder);
    const graphResult = await this.GraphModel.save(graph);
    if (graphResult) {
      this.createMiniTask(diffResult.added, graphData, graph);
      this.deleteMiniTask(diffResult.removed);
      return { success: true, data: graphResult, message: '图谱编辑成功 ' };
    } else {
      return { success: false, message: '图谱编辑失败 ' };
    }
  }

  async findArrayDiff(A, B) {
    const added = [];
    const removed = [];
    const common = [];

    for (const element of B) {
      if (!A.includes(element)) {
        added.push(element);
      }
    }

    for (const element of A) {
      if (!B.includes(element)) {
        removed.push(element);
      } else {
        common.push(element);
      }
    }
    console.log(added);
    console.log(removed);
    console.log(common);
    return { added, removed, common };
  }

  createMiniTask(executionOrder: string[], graphData: any, graph: Graph) {
    executionOrder.length > 0 &&
      executionOrder.forEach(async id => {
        let node = graphData.cells.find(item => {
          return item.id == id;
        });
        const algorithm = await this.AlgorithmModel.findOne({
          where: {
            id: node.data.id,
          },
        });
        let miniTask = new MiniTask();
        miniTask.id = node.id;
        miniTask.graphId = graph.id;
        miniTask.algorithmId = node.data.id;
        miniTask.runTimeParams = algorithm.parameters;
        this.MiniTaskModel.save(miniTask);
      });
  }

  deleteMiniTask(executionOrder) {
    executionOrder.length > 0 &&
      executionOrder.forEach(async id => {
        const miniTask = await this.MiniTaskModel.findOne({
          where: {
            id,
          },
        });
        let result = await this.MiniTaskModel.remove(miniTask);
        return {
          succes: true,
          data: result,
          message: '删除成功',
        };
      });
  }

  async executeGraph(id: number) {
    const graph = await this.GraphModel.findOne({
      where: {
        id,
      },
    });
    if (!graph) {
      return {
        succes: false,
        message: '未查询到算法流程',
      };
    }
    const flow = JSON.parse(graph.flow);
    await this.resetAllStatus(graph);
    for (const id of flow) {
      await this.processMiniTask(id, graph);
    }
    console.log('所有异步任务完成');
  }

  async invoke(graphId) {
    this.wsApp.clients.forEach(ws => {
      const message = { cmd: 'graph', graphId, action: 'refresh' };
      ws.send(JSON.stringify(message));
    });
  }

  async processMiniTask(id: string, process: Graph) {
    const miniTask = await this.MiniTaskModel.findOne({
      where: {
        id,
      },
    });

    const algorithm = await this.AlgorithmModel.findOne({
      where: { id: miniTask.algorithmId },
    });

    if (!algorithm) {
      return {
        success: false,
        message: '未找到要执行的算法',
      };
    }
    switch (algorithm.executeType) {
      case 1:
        await this.normalExecute(algorithm, miniTask, id, process);
        break;
      case 2:
        await this.tifPublishExecute(algorithm, miniTask, id, process);
        break;
      case 3:
        await this.publishShpFile(algorithm, miniTask, process);
        break;
      case 4:
        await this.bindStyleToLayer(algorithm, miniTask, process);
        break;
      case 5:
        await this.previewResult(miniTask, process); //预览tif+shp
        break;
      case 6:
        await this.pushMPDIResult(miniTask, process);
        break;
      case 7:
        await this.createBatchCatalogue(miniTask, process);
        break;
      case 9:
        await this.generalBatchTask(miniTask, process); //通用批处理算法
        break;
      case 10:
        await this.batchCatalogueByDir(miniTask, process); //批处理目录生成
        break;
      case 11:
        await this.executeMatlabAlgorithm(miniTask, process); //matlab算法执行
        break;
      default:
        break;
    }
  }

  replace(json: any, filter: any[]) {
    if (filter && filter.length > 0) {
      for (const replacement of filter) {
        const { name, value } = replacement;
        for (const key in json) {
          if (typeof json[key] === 'string') {
            json[key] = json[key].replace(new RegExp(name, 'g'), value);
          }
        }
      }
    }
    return json;
  }


  async normalExecute(
    algorithm: Algorithm,
    miniTask: MiniTask,
    id: string,
    process: Graph
  ) {
    const exePath = algorithm.application;
    const parameters = JSON.parse(miniTask.runTimeParams);
    const parametersParsed = this.convertJsonArrayToObject(parameters);
    const jsonParameterFiltered = this.replace(parametersParsed, JSON.parse(process.dynamic))
    console.log(JSON.parse(process.dynamic))
    console.log(jsonParameterFiltered)
    // 使用child_process.spawn执行exe程序
    this.changeGraphStatus(id, process, 'running');
    return new Promise((resolve, reject) => {
      const child = childProcess.spawn(exePath, [JSON.stringify(jsonParameterFiltered)]);
      let logOutput = ''; // 用于保存日志信息
      // 监听子进程的标准输出
      child.stdout.on('data', data => {
        logOutput += data.toString('utf-8');
        let log = data.toString('utf-8');
        console.log(log)
      });
      // 监听子进程的标准错误输出
      child.stderr.on('data', data => {
        logOutput += data.toString('utf-8');
        console.log(data.toString('utf-8'));
        // this.changeGraphStatus(id, process, 'failed');
      });



      child.on('exit', code => {
        console.log('算法执行完成');
        if (miniTask.pause == false) {
          this.changeGraphStatus(id, process, 'success');
          resolve('success');
        } else {
          this.changeGraphStatus(id, process, 'pause');
          this.promiseService.createPromise(miniTask.id).then(() => {
            console.log('算法执行完成');
            this.changeGraphStatus(id, process, 'success');
            resolve('success');
          });
        }
      });


    });
  }


  async tifPublishExecute(
    algorithm: Algorithm,
    miniTask: MiniTask,
    id: string,
    process: Graph
  ) {
    const parameters = JSON.parse(miniTask.runTimeParams);
    const parametersParsed = this.convertJsonArrayToObject(parameters);
    const jsonParameterFiltered = this.replace(parametersParsed, JSON.parse(process.dynamic))
    const workspace = 'result';
    this.changeGraphStatus(id, process, 'running');
    const tifFilePath = jsonParameterFiltered.image_path;
    let { name } = path.parse(tifFilePath);
    const layerName = name;
    // GeoServer 的认证信息，如果不需要认证，可以将这部分省略
    const username = 'admin';
    const password = 'geoserver';
    const restUrl = `${algorithm.application}/geoserver/rest/workspaces/${workspace}/coveragestores/${layerName}/file.geotiff`;
    // 构造认证信息
    const auth = `${username}:${password}`;
    const url = `${algorithm.application}/geoserver/rest/workspaces/${workspace}/datastores/${layerName}`;
    try {
      const response = await axios.delete(url, {
        // 添加请求头，例如授权信息等
        headers: {
          Authorization: `Basic ${Buffer.from(auth).toString('base64')}`,
        },
      });
      console.log('删除数据存储成功');
    } catch (error) {
      console.error('删除数据存储失败');
    }
    return new Promise(async resolve => {
      setTimeout(async () => {
        const fileData = await fs.promises.readFile(tifFilePath);
        const response = await axios.put(restUrl, fileData, {
          headers: {
            'Content-Type': 'image/tiff',
            Authorization: `Basic ${Buffer.from(auth).toString('base64')}`,
          },
        });
        if (response) {
          if (miniTask.pause == false) {
            this.changeGraphStatus(id, process, 'success');
            resolve('success');
          } else {
            this.changeGraphStatus(id, process, 'pause');
            this.promiseService.createPromise(miniTask.id).then(() => {
              console.log('算法执行完成');
              this.changeGraphStatus(id, process, 'success');
              resolve('success');
            });
          }
        }
      }, 4000);
    });
  }

  async publishShpFile(
    algorithm: Algorithm,
    miniTask: MiniTask,
    process: Graph
  ) {
    const parameters = JSON.parse(miniTask.runTimeParams);
    let parsedParams = this.convertJsonArrayToObject(parameters);
    const jsonParameterFiltered = this.replace(parsedParams, JSON.parse(process.dynamic))
    console.log(jsonParameterFiltered);
    const shpPath = jsonParameterFiltered.shp_path;
    let { name, dir } = path.parse(shpPath);
    const shpZipFile = `${dir}/${name}_shp.zip`;
    this.changeGraphStatus(miniTask.id, process, 'running');
    return await this.compressShpToZip(
      shpPath,
      shpZipFile,
      name,
      miniTask,
      algorithm,
      process
    );
  }

  async compressShpToZip(
    shpFilePath: string,
    outputZipPath: string,
    shpName: string,
    miniTask: MiniTask,
    algorithm: Algorithm,
    process: Graph
  ) {
    const self = this;
    return new Promise(async (resolve, reject) => {
      // 创建一个输出流到指定的 ZIP 文件
      const output = fs.createWriteStream(outputZipPath);
      const archive = archiver('zip', {
        zlib: { level: 9 }, // 设置压缩级别
      });

      // 监听错误事件
      output.on('error', function (err) {
        reject(err);
      });

      // 监听关闭事件
      output.on('close', async function () {
        console.log(archive.pointer() + ' total bytes');
        let result = await self.publishShpToGeoServer(
          outputZipPath,
          shpName,
          miniTask,
          algorithm,
          process
        );
        resolve(result);
      });

      // 绑定输出流到压缩程序
      archive.pipe(output);

      // 获取文件名
      const shpFileName = shpFilePath.split('/').pop().replace('.shp', '');
      // 将与 .shp 文件同名的文件（除了 .zip 文件）添加到压缩程序
      const shpFileDir = path.dirname(shpFilePath);
      return await fs.readdir(shpFileDir, async (err, files) => {
        if (err) {
          reject(err);
        } else {
          files.forEach(file => {
            if (
              (file.startsWith(shpFileName) && file.endsWith('.shx')) ||
              file.endsWith('.dbf') ||
              file.endsWith('.shp') ||
              file.endsWith('.prj')
            ) {
              console.log(file);
              const filePath = path.join(shpFileDir, file);
              const pathObj = path.parse(file);
              const newFileName = pathObj.name + '_shp' + pathObj.ext;
              archive.file(filePath, { name: newFileName });
            }
          });
          // 完成压缩
          await archive.finalize();
        }
      });
    });
  }

  private async publishShpToGeoServer(
    shpFilePath: string,
    shpName: string,
    miniTask: MiniTask,
    algorithm: Algorithm,
    process: Graph
  ) {
    const workspace = 'result';
    const layerName = shpName + '_shp';

    // GeoServer 的认证信息，如果不需要认证，可以将这部分省略
    const username = 'admin';
    const password = 'geoserver';

    const restUrl = `${algorithm.application}/geoserver/rest/workspaces/${workspace}/datastores/${layerName}/file.shp`;

    // 构造认证信息
    const auth = `${username}:${password}`;

    return new Promise(async resolve => {
      const fileData = await fs.promises.readFile(shpFilePath);

      const response = await axios.put(restUrl, fileData, {
        headers: {
          'Content-Type': 'application/zip',
          Authorization: `Basic ${Buffer.from(auth).toString('base64')}`,
        },
      });

      console.log('Shapefile 成功发布到 GeoServer!');
      await setTimeout(() => {
        if (miniTask.pause == false) {
          this.changeGraphStatus(miniTask.id, process, 'success');
          resolve('success');
        } else {
          this.changeGraphStatus(miniTask.id, process, 'pause');
          this.promiseService.createPromise(miniTask.id).then(() => {
            console.log('算法执行完成');
            this.changeGraphStatus(miniTask.id, process, 'success');
            resolve('success');
          });
        }
      }, 2000);
    });
  }

  async bindStyleToLayer(
    algorithm: Algorithm,
    miniTask: MiniTask,
    process: Graph
  ) {
    return new Promise(async (resolve, reject) => {
      try {
        this.changeGraphStatus(miniTask.id, process, 'running');
        // GeoServer 的认证信息，如果不需要认证，可以将这部分省略
        const username = 'admin';
        const password = 'geoserver';
        // 构造认证信息
        const auth = `${username}:${password}`;
        const geoserverUrl = algorithm.application; // GeoServer 的 URL
        const workspace = 'result'; // 工作区名称
        const parameters = JSON.parse(miniTask.runTimeParams);
        let parsedParams = this.convertJsonArrayToObject(parameters);
        const jsonParameterFiltered = this.replace(parsedParams, JSON.parse(process.dynamic))
        console.log(jsonParameterFiltered);
        const layerName = jsonParameterFiltered.layer_name;
        const styleName = jsonParameterFiltered.style_name;
        const data = {
          layer: {
            defaultStyle: {
              name: styleName,
            },
          },
        };
        // 发送 PUT 请求将样式应用到图层
        let response = await axios.put(
          `${geoserverUrl}/geoserver/rest/layers/${workspace}:${layerName}`,
          data,
          {
            headers: {
              'Content-Type': 'application/json',
              Authorization: `Basic ${Buffer.from(auth).toString('base64')}`,
            },
          }
        );
        if (response.status == 200) {
          if (miniTask.pause == false) {
            this.changeGraphStatus(miniTask.id, process, 'success');
            resolve('success');
          } else {
            this.changeGraphStatus(miniTask.id, process, 'pause');
            this.promiseService.createPromise(miniTask.id).then(() => {
              console.log('算法执行完成');
              this.changeGraphStatus(miniTask.id, process, 'success');
              resolve('success');
            });
          }
        } else {
          this.changeGraphStatus(miniTask.id, process, 'error');
          resolve('success');
        }
      } catch (error) {
        this.changeGraphStatus(miniTask.id, process, 'error');
        console.error('图层样式绑定失败', error);
        reject(error);
      }
    });
  }

  async previewResult(miniTask: MiniTask, process: Graph) {
    this.changeGraphStatus(miniTask.id, process, 'running');
    return new Promise((resolve, reject) => {
      setTimeout(async () => {
        this.changeGraphStatus(miniTask.id, process, 'success');
        if (miniTask.pause == false) {
          this.changeGraphStatus(miniTask.id, process, 'success');
          resolve('success');
        } else {
          this.changeGraphStatus(miniTask.id, process, 'pause');
          this.promiseService.createPromise(miniTask.id).then(() => {
            console.log('算法执行完成');
            this.changeGraphStatus(miniTask.id, process, 'success');
            resolve('success');
          });
        }
      }, 4000);
    });
  }

  @InjectEntityModel(M1Product)
  M1ProductModel: Repository<M1Product>;

  async pushMPDIResult(miniTask: MiniTask, process: Graph) {
    this.changeGraphStatus(miniTask.id, process, 'running');
    return new Promise((resolve, reject) => {
      setTimeout(async () => {
        const parameters = JSON.parse(miniTask.runTimeParams);
        const parametersParsed = this.convertJsonArrayToObject(parameters);
        const jsonParameterFiltered = this.replace(parametersParsed, JSON.parse(process.dynamic))
        const m1Product = new M1Product();
        m1Product.box = JSON.stringify([jsonParameterFiltered.minX, jsonParameterFiltered.minY, jsonParameterFiltered.maxX, jsonParameterFiltered.maxY])
        m1Product.productName = jsonParameterFiltered.origin_img
        m1Product.step1 = jsonParameterFiltered.origin_img
        m1Product.step2 = jsonParameterFiltered.after_img
        m1Product.step3 = jsonParameterFiltered.MPDI_product
        m1Product.step4 = jsonParameterFiltered.soil_water
        m1Product.step5 = jsonParameterFiltered.calc
        m1Product.satelliteType = jsonParameterFiltered.satelliteType
        m1Product.produceDate = jsonParameterFiltered.produceDate
        this.M1ProductModel.save(m1Product)
        if (miniTask.pause == false) {
          this.changeGraphStatus(miniTask.id, process, 'success');
          resolve('success');
        } else {
          this.changeGraphStatus(miniTask.id, process, 'pause');
          this.promiseService.createPromise(miniTask.id).then(() => {
            console.log('算法执行完成');
            this.changeGraphStatus(miniTask.id, process, 'success');
            resolve('success');
          });
        }
      }, 4000);
    });
  }

  async createBatchCatalogue(miniTask: MiniTask, process: Graph) {
    this.changeGraphStatus(miniTask.id, process, 'running');
    return new Promise(async (resolve, reject) => {
      const parameters = JSON.parse(miniTask.runTimeParams);
      const parametersParsed = this.convertJsonArrayToObject(parameters);
      const jsonParameterFiltered = this.replace(parametersParsed, JSON.parse(process.dynamic))
      try {
        setTimeout(async () => {
          const { outputFile } = jsonParameterFiltered;
          console.log(outputFile)
          // 将对象转换为 JSON 字符串
          const jsonContent = JSON.stringify(jsonParameterFiltered, null, 2);
          // 确保目录存在，如果不存在则创建
          const dir = path.dirname(outputFile);
          if (!fs.existsSync(dir)) {
            fs.mkdirSync(dir, { recursive: true });
          }
          // 将 JSON 字符串写入指定路径的文件
          await fs.promises.writeFile(outputFile, jsonContent, 'utf8');
          if (miniTask.pause == false) {
            this.changeGraphStatus(miniTask.id, process, 'success');
            resolve('success');
          } else {
            this.changeGraphStatus(miniTask.id, process, 'pause');
            this.promiseService.createPromise(miniTask.id).then(() => {
              console.log('算法执行完成');
              this.changeGraphStatus(miniTask.id, process, 'success');
              resolve('success');
            });
          }
        }, 3000)
        // 返回成功消息和 JSON 文件路径
      } catch (error) {
        this.changeGraphStatus(miniTask.id, process, 'error');
        console.error('Error:', error);
      }
    });
  }

  async generalBatchTask(miniTask: MiniTask, process: Graph) {
    this.changeGraphStatus(miniTask.id, process, 'running');
    return new Promise(async (resolve, reject) => {
      const parameters = JSON.parse(miniTask.runTimeParams);
      const parametersParsed = this.convertJsonArrayToObject(parameters);
      const jsonParameterFiltered = this.replace(parametersParsed, JSON.parse(process.dynamic))
      const outputDir = jsonParameterFiltered.outputDir;
      const outputSuffix = jsonParameterFiltered.outputSuffix;
      const outputType = jsonParameterFiltered.outputType;
      const algorithmId = jsonParameterFiltered.algorithm;
      const runtimeParams = jsonParameterFiltered.runtimeParams
      const runtimeParamsParsed = this.convertJsonArrayToObject(runtimeParams);
      const algorithm = await this.AlgorithmModel.findOne({
        where: {
          id: algorithmId,
        },
      });
      fs.readFile(jsonParameterFiltered.inputFile, 'utf8', async (err, data) => {
        if (err) {
          console.error('Error reading input file:', err);
          return reject(err);
        }
        const jsonContent = JSON.parse(data);
        const files = jsonContent.files;

        const promises = files.map((file, index) => {
          return new Promise((resolve, reject) => {
            const { name } = path.parse(file);
            const exePath = algorithm.application;
            runtimeParamsParsed.inputFile = file;
            runtimeParamsParsed.outputFile = `${outputDir}/${name}${outputSuffix}${outputType}`;
            const runtimeParamsParsedFiltered = this.replace(runtimeParamsParsed, JSON.parse(process.dynamic))
            const child = childProcess.spawn(exePath, [JSON.stringify(runtimeParamsParsedFiltered)]);
            console.log(exePath)
            console.log(JSON.stringify(runtimeParamsParsedFiltered))
            let logOutput = ''; // 用于保存日志信息
            // 监听子进程的标准输出
            child.stdout.on('data', data => {
              logOutput += data.toString('utf-8');
              let log = data.toString('utf-8');
              console.log(log)
            });
            // 监听子进程的标准错误输出
            child.stderr.on('data', data => {
              logOutput += data.toString('utf-8');
              console.log(data.toString('utf-8'));
            });
            child.on('error', (err) => {
              console.error('Failed to start subprocess.');
              console.error(err);
            });
            child.on('exit', async code => {
              console.log('算法执行完成');
              resolve('success');
            });
          });
        });

        try {
          await Promise.all(promises);
          console.log(`算法全部执行完成`);
          if (miniTask.pause == false) {
            this.changeGraphStatus(miniTask.id, process, 'success');
            resolve('success');
          } else {
            this.changeGraphStatus(miniTask.id, process, 'pause');
            this.promiseService.createPromise(miniTask.id).then(() => {
              console.log('算法执行完成');
              this.changeGraphStatus(miniTask.id, process, 'success');
              resolve('success');
            });
          }
        } catch (error) {
          this.changeGraphStatus(miniTask.id, process, 'error');
          reject(error);
          console.log(error)
        }
      });

    });
  }

  async batchCatalogueByDir(miniTask: MiniTask, process: Graph) {
    this.changeGraphStatus(miniTask.id, process, 'running');
    return new Promise((resolve, reject) => {
      setTimeout(async () => {
        const parameters = JSON.parse(miniTask.runTimeParams);
        const parametersParsed = this.convertJsonArrayToObject(parameters);
        const jsonParameterFiltered = this.replace(parametersParsed, JSON.parse(process.dynamic))
        console.log(jsonParameterFiltered)
        let folderPath = jsonParameterFiltered.Dir
        let type = [jsonParameterFiltered.fileType]
        // 检查文件夹路径是否存在
        if (!fs.existsSync(folderPath)) {
          return { message: '文件夹不存在' };
        }
        // 读取文件夹中的文件列表
        const files = await fs.promises.readdir(folderPath);
        const fileList: any[] = [];
        for (const file of files) {
          const filePath = path.join(folderPath, file).replace(/\\/g, '/');
          const stats = await fs.promises.stat(filePath);
          // 如果文件不是文件夹，并且文件扩展名在指定类型中，则将其添加到文件列表中
          if (!stats.isDirectory()) {
            if (type.length > 0) {
              type.indexOf(path.extname(file)) !== -1 && fileList.push(filePath);
            }
          }
        }
        let outputFile = jsonParameterFiltered.outputFile
        console.log(outputFile)
        // 返回文件列表
        let Content = { files: fileList, outputFile };

        // 将对象转换为 JSON 字符串
        const jsonContent = JSON.stringify(Content, null, 2);

        // 确保目录存在，如果不存在则创建
        const dir = path.dirname(outputFile);
        if (!fs.existsSync(dir)) {
          fs.mkdirSync(dir, { recursive: true });
        }
        // 将 JSON 字符串写入指定路径的文件
        await fs.promises.writeFile(outputFile, jsonContent, 'utf8');
        if (miniTask.pause == false) {
          this.changeGraphStatus(miniTask.id, process, 'success');
          resolve('success');
        } else {
          this.changeGraphStatus(miniTask.id, process, 'pause');
          this.promiseService.createPromise(miniTask.id).then(() => {
            console.log('算法执行完成');
            this.changeGraphStatus(miniTask.id, process, 'success');
            resolve('success');
          });
        }
      }, 4000);
    });
  }

  async executeMatlabAlgorithm(miniTask: MiniTask, process: Graph) {
    this.changeGraphStatus(miniTask.id, process, 'running');
    const algorithm = await this.AlgorithmModel.findOne({
      where: {
        id: miniTask.algorithmId,
      },
    });
    return new Promise((resolve, reject) => {
      const exePath = algorithm.application;
      const parameters = JSON.parse(miniTask.runTimeParams);
      const parametersParsed = this.convertJsonArrayToObject(parameters);
      const jsonParameterFiltered = this.replace(parametersParsed, JSON.parse(process.dynamic))
      jsonParameterFiltered.task_id = (miniTask.id).toString()
      const now = new Date();
      const timestamp = `${now.getHours()}-${now.getMinutes()}-${now.getSeconds()}`;
      const fileName = `runtime_params_${miniTask.id}_${timestamp}.json`;
      const filePath = path.join('D:/matlabCode/model_1/xjet', fileName);
      fs.writeFile(filePath, JSON.stringify(jsonParameterFiltered, null, 2), (err) => {
        if (err) {
          reject(err);
          return;
        }

        const jsonFilePath = filePath;
        const addpath = path.dirname(exePath);
        const mainFunction = path.basename(exePath, '.m');
        const matlabCommand = `jsonFilePath = '${jsonFilePath}'; addpath('${addpath}'); ${mainFunction}(jsonFilePath); exit`;
        const child = childProcess.spawn(this.matlabExePath, ['-nodisplay', '-nosplash', '-nodesktop', '-r', matlabCommand]);
        let logOutput = ''; // 用于保存日志信息

        // 监听子进程的标准输出
        child.stdout.on('data', data => {
          logOutput += data.toString('utf-8');
          let log = data.toString('utf-8');
          console.log(log); // 输出日志到控制台
        });

        // 监听子进程的标准错误输出
        child.stderr.on('data', data => {
          logOutput += data.toString('utf-8');
          console.error(data.toString('utf-8'));
        });

        // 监听子进程的退出事件
        child.on('exit', async code => {
        });
        this.promiseService.createPromise((miniTask.id).toString()).then(() => {
          console.log('算法执行完成');
          if (miniTask.pause == false) {
            this.changeGraphStatus(miniTask.id, process, 'success');
            resolve('success');
          } else {
            this.changeGraphStatus(miniTask.id, process, 'pause');
            this.promiseService.createPromise(miniTask.id).then(() => {
              console.log('算法执行完成');
              this.changeGraphStatus(miniTask.id, process, 'success');
              resolve('success');
            });
          }
          fs.unlink(jsonFilePath, (err) => { });
        });

        // 监听子进程的错误事件
        child.on('error', err => {
          console.error('子进程错误:', err);
          reject(err);
        });
      });
    });
  }


  async deleteGraph(id: number) {
    const graph = await this.GraphModel.findOne({
      where: {
        id,
      },
    });
    if (!graph) {
      return {
        succes: false,
        message: '未查询到算法流程',
      };
    }
    let result = await this.GraphModel.remove(graph);
    let MiniTasks = await this.MiniTaskModel.find({
      where: {
        graphId: id,
      },
    });
    MiniTasks.forEach(miniTask => {
      this.MiniTaskModel.remove(miniTask);
    });
    return {
      succes: true,
      data: result,
      message: '删除成功',
    };
  }

  async getNodeParams(id: number, nodeId: string) {
    let miniTask = await this.MiniTaskModel.findOne({
      where: {
        id: nodeId,
        graphId: id,
      },
    });
    if (!miniTask) {
      return {
        succes: false,
        message: '未查询到算法参数',
      };
    }
    return {
      succes: true,
      data: miniTask,
      message: '查询成功',
    };
  }

  async updateNodeParams(id: number, node: IAlgorithmParams) {
    let miniTask = await this.MiniTaskModel.findOne({
      where: {
        id: node.id,
        graphId: id,
      },
    });
    if (!miniTask) {
      return {
        succes: false,
        message: '未查询到算法参数',
      };
    }
    miniTask.runTimeParams = node.runTimeParams;
    let result = this.MiniTaskModel.save(miniTask);
    return {
      succes: true,
      data: result,
      message: '参数修改成功',
    };
  }

  async changePauseStatus(id: number, params: any) {
    let miniTask = await this.MiniTaskModel.findOne({
      where: {
        id: params.id,
        graphId: id,
      },
    });
    if (!miniTask) {
      return {
        succes: false,
        message: '未查询到算法参数',
      };
    }
    miniTask.pause = params.status;
    let result = this.MiniTaskModel.save(miniTask);
    return {
      succes: true,
      data: result,
      message: '暂停状态修改成功',
    };
  }

  private async changeGraphStatus(
    miniTaskId: string,
    process: Graph,
    status: string
  ) {
    let graph = JSON.parse(process.graph);
    graph.cells.forEach(element => {
      if (element.id == miniTaskId) {
        element.data.status = status;
      }
    });
    process.graph = JSON.stringify(graph);
    await this.GraphModel.save(process);
    await this.invoke(process.id);
  }
  async resetAllStatus(process: Graph) {
    let graph = JSON.parse(process.graph);
    graph.cells.forEach(async element => {
      if (element.shape != 'edge') {
        element.data.status = 'pennding';
        process.graph = JSON.stringify(graph);
        await this.GraphModel.save(process);
        await this.invoke(process.id);
      }
    });
  }

  private extractNumberFromString(str: string): number | null {
    const regex = /(\d+)%/;
    const match = str.match(regex);
    console.log('match' + match);
    let percentage = null;
    if (match) {
      percentage = parseInt(match[1]);
      return percentage;
    }
    return null; // 如果没有找到数字或字符串不符合格式，则返回 null
  }

  private convertJsonArrayToObject(jsonArray) {
    return jsonArray.reduce((result, item) => {
      result[item.param_name] = item.default_value;
      return result;
    }, {});
  }
  private topologicalSort(edges) {
    const graph = {};
    const inDegree = {};

    // 构建图形表示和入度计数
    edges.forEach(edge => {
      const source = edge.source.cell;
      const target = edge.target.cell;

      if (!graph[source]) {
        graph[source] = [];
      }
      graph[source].push(target);

      inDegree[target] = inDegree[target] ? inDegree[target] + 1 : 1;
    });

    const queue = [];
    const executionOrder = [];

    // 将入度为0的节点加入队列
    for (const node in graph) {
      if (!inDegree[node]) {
        queue.push(node);
      }
    }

    // 拓扑排序
    while (queue.length) {
      const node = queue.shift();
      executionOrder.push(node);

      if (graph[node]) {
        graph[node].forEach(neighbor => {
          inDegree[neighbor]--;

          if (inDegree[neighbor] === 0) {
            queue.push(neighbor);
          }
        });
      }
    }

    return executionOrder;
  }
}
